package cn.buk.tms.dao;

import static cn.buk.tms.entity.misc.User.SEARCH_MODE_EMPLOYEE;
import static cn.buk.tms.entity.misc.User.SEARCH_MODE_MEMBER;
import static cn.buk.tms.common.constant.TmsOrderConstant.OPERATING_OBJECT_BASIC_DATA;

import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.common.sc.Page;
import cn.buk.common.util.DateUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jakarta.persistence.Query;
import jakarta.persistence.criteria.*;
import jakarta.transaction.Transactional;

import cn.buk.tms.entity.misc.*;
import cn.buk.tms.sc.SearchUserCriteria;
import org.springframework.stereotype.Component;

/**
 * @author yfdai
 */
@Component
@Transactional
public class UserDaoImpl extends AbstractDao implements UserDao {

  /**
   * 创建新用户
   */
  @Override
  public int createUser(User user, final String invitationCode) {
    if (user == null) {
      throw new RuntimeException("user cannot be null.");
    }

    if (user.getMd5Password() == null) {
      throw new RuntimeException("Password(md5) cannot be null.");
    }

    em.persist(user);

    if (user.getEnterprise() == null) {
      //新注册用户，自动成为企业用户，但用户数只能为1
      Enterprise enterprise = new Enterprise();
      enterprise.setId(user.getId());
      enterprise.setName(user.getUsername());
      enterprise.setUserCount(1);
      enterprise.setInvitationCode(invitationCode);

      em.persist(enterprise);

      user.setEnterprise(enterprise);
      em.merge(user);
    }

    return user.getId();
  }

  @Override
  public int createTmcUser(final int enterpriseId, User user, Customer c) {
    user.setParentEnterprise(enterpriseId);

    if (user.getMd5Password() == null) {
      throw new RuntimeException("Password(md5) cannot be null.");
    }

    em.persist(user);
    em.flush();

    //新注册用户，自动成为企业用户
    Enterprise enterprise = new Enterprise();
    enterprise.setParentEnterprise(enterpriseId);
    enterprise.setId(user.getId());
    enterprise.setName(user.getEmpname());
    enterprise.setUserCount(100);
    em.persist(enterprise);
    em.flush();

    user.setEnterprise(enterprise);
    em.merge(user);
    em.flush();

    // 为了和 plutus 兼容，向t102(customer)中也增加一条记录, customer中可以保存更多的企业客户资料
    //Customer c = new Customer();
    c.setEnterpriseId(enterpriseId);
    c.setCustomerEnterpriseId(user.getId());
    c.setVipName(user.getEmpname());
    em.persist(c);
    em.flush();

    return user.getId();
  }

  @Override
  public int createPassengerUser(User user, Passenger passenger, User newUser) {
    em.persist(newUser);

    OperationLog log = OperationLog.createLog(user.getEnterpriseId(), OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(user.getUsername());
    log.setContent("为企业(" + passenger.getCustomer().getVipName() + ")的员工(" + passenger.getNameCn() + ")生成登录用户名(" + newUser.getUsername() + ").");
    em.persist(log);

    return newUser.getId();
  }

  private List<Predicate> buildPredicates_search(CriteriaBuilder cb,
                                                               Root<User> root,
                                                              final int enterpriseId, SearchUserCriteria sc, final int mode) {
    List<Predicate> predicates = new ArrayList<>();
    Predicate where = cb.conjunction();
    predicates.add(where);

    if (mode == SEARCH_MODE_EMPLOYEE) {
      // 搜索员工
      where = cb.equal(root.get(User_.enterpriseId), enterpriseId);
      predicates.add(where);
    } else if (mode == SEARCH_MODE_MEMBER) {
      // 搜索会员
      where = cb.equal(root.get(User_.parentEnterprise), enterpriseId);
      predicates.add(where);
    }

    if (sc.getUsername() != null && sc.getUsername().trim().length() > 0) {
      where = cb.like(root.get(User_.username), "%" + sc.getUsername() + "%");
      predicates.add(where);
    }

    if (sc.getMobile() != null && sc.getMobile().trim().length() > 0) {
      where = cb.like(root.get(User_.mobileNo), "%" + sc.getMobile() + "%");
      predicates.add(where);
    }

    if (sc.getType() == User.USER_TYPE_PSG || sc.getType() == User.USER_TYPE_ENT) {
      where = cb.equal(root.get(User_.userType), sc.getType());
      predicates.add(where);
    }

    if (sc.getEtermUsername() != null && sc.getEtermUsername().trim().length() > 0) {
      where = cb.like(root.get(User_.etermUsername), '%' + sc.getEtermUsername().trim().toUpperCase() + '%');
      predicates.add(where);
    }

    if (sc.getStatus() >= 0) {
      where = cb.equal(root.get(User_.status), sc.getStatus());
      if (sc.getStatus() == 1) {
        where = cb.or(where, cb.isNull(root.get(User_.status)));
      }
      predicates.add(where);
    }

    if (sc.getGrouped() == 1) {
      where = cb.isNotNull(root.get(User_.customerServiceGroupCode));
      predicates.add(where);
    } else if (sc.getGrouped() == 0) {
      where = cb.isNull(root.get(User_.customerServiceGroupCode));
      predicates.add(where);
    }

    return predicates;
  }

  /**
   * 查找用户（员工或会员）
   *
   * @param enterpriseId 企业id
   * @param sc           查询条件
   * @param mode         查询模式 0-员工，1-会员
   */
  @Override
  public List<User> search(final int enterpriseId, SearchUserCriteria sc, final int mode) {
    List<User> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<User> cq = cb.createQuery(User.class);
    Root<User> root = cq.from(User.class);
    root.alias("o");

    var predicates0 = buildPredicates_search(cb, root, enterpriseId, sc, mode);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<User> countRoot = countQuery.from(User.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_search(cb, countRoot, enterpriseId, sc, mode);

    countQuery.select(cb.count(countRoot)).where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    if (count.intValue() > 0) {
      cq.where(predicates0.toArray(new Predicate[predicates0.size()]));
      List<Order> orderByes = new ArrayList<>();
      if (mode == 0) {
        orderByes.add(cb.asc(root.get(User_.status)));
        orderByes.add(cb.asc(root.get(User_.username)));
      } else if (mode == 1) {
        orderByes.add(cb.asc(root.get(User_.enterprise)));
        orderByes.add(cb.asc(root.get(User_.id)));
      }

      cq.orderBy(orderByes);

      Page page = sc.getPage();
      page.setRowCount(count.intValue());
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      results = em.createQuery(cq)
              .setFirstResult(i)
              .setMaxResults(page.getPageSize()).getResultList();
    }

    return results == null ? new ArrayList<>() : results;
  }

  /**
   * 查找所有员工账号
   */
  @Override
  public List<User> searchEmployees(int enterpriseId) {
    return em.createQuery("select o from User o where o.enterpriseId = :enterpriseId", User.class)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }


  /**
   * 修改用户密码
   *
   * @param md5Password  md5后的新密码
   */
  @Override
  public int updateUserPassword(int enterpriseId, int userId, String username, String md5Password) {
    int retCode = em.createQuery(
            "update User o set o.password = null, o.md5Password = :md5 where o.id = :id and o.username = :username")
            .setParameter("id", userId)
            .setParameter("username", username)
            .setParameter("md5", md5Password)
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("To update password failed.");
    }

    // 记录日志
    LoginHistory log = new LoginHistory();
    log.setEnterpriseId(enterpriseId);
    log.setUsername(username);
    log.setMemo("修改密码");

    em.persist(log);

    return retCode;
  }

  @Override
  public int updateUserPassword(int userId, String newPasswordMd5) {
    return em.createQuery("update User o set o.password = null, o.md5Password = :newPwd where o.id = :id")
            .setParameter("id", userId)
            .setParameter("newPwd", newPasswordMd5)
            .executeUpdate();
  }

  @Override
  public boolean isUsernameExisted(String username) {
    boolean result = false;

    List<User> users = em.createQuery("select u from User u where u.username = ?1", User.class)
            .setParameter(1, username)
            .getResultList();

    result = users.size() > 0;


    return result;
  }


  /**
   * 校验手机上是否在系统中已经使用过
   */
  @Override
  public boolean isMobileVerified(String mobileNo, final int userType) {
    List<User> users = em.createQuery("select u from User u where u.mobileNo = :mobileNo " +
            " and (u.mobilePhoneVerified = :status1 or u.mobilePhoneVerified = :status2) " +
            " and u.userType = :userType", User.class)
            .setParameter("mobileNo", mobileNo)
            .setParameter("status1", User.USER_MOBILE_VERIFIED)
            .setParameter("status2", User.USER_MOBILE_REGISTERED)
            .setParameter("userType", userType)
            .getResultList();

    return users.size() > 0;
  }


  /**
   * 根据用户名查找用户
   *
   * @param username 查询对应的用户名
   * @return 具体的用户名
   */
  @Override
  public User getUserByUsername(String username) {
    List<User> list = em.createQuery("select u from User u where u.username = :username", User.class)
            .setParameter("username", username)
            .getResultList();

    return list.size() == 0 ? null : list.get(0);
  }


  /**
   * 通过用户查找
   */
  @Override
  public User getUserById(int id) {

    User u = em.find(User.class, id);
    if (u == null) {
      return null;
    }
    em.refresh(u);

    return u;

  }

  @Override
  public User getUserByUsername(String username, int enterpriseId) {
    List<User> users = em.createQuery("select o from User o where o.username = :username and o.enterprise.id = :enterpriseId", User.class)
            .setParameter("username", username)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();

    return users.isEmpty() ? null : users.get(0);
  }

  @Override
  public User getUserByUsername(String username, int userType, int enterpriseId) {
    String jql = "select o from User o where o.username = :username" +
            " and o.enterprise.id = :enterpriseId" +
            " and o.userType = :userType";


    Query query = em.createQuery(jql);
    query.setParameter("username", username)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("userType", userType);

    @SuppressWarnings("unchecked")
    List<User> users = query.getResultList();
    assert users.size() <= 1 : "returned " + users.size() + " users"; // sanity
    // check
    return users.isEmpty() ? null : users.get(0);


  }

  /**
   * 用手机号查找用户信息
   *
   * @param ownerId  当前应用id
   * @param mobile   手机号
   * @param userType 用户类型
   */
  @Override
  public User getUserByMobile(final int ownerId, final String mobile, final int userType) {
    if (ownerId == 0) {
      List<User> users = em.createQuery("select o from User o " +
              "where o.mobileNo = :mobile" +
              " and o.parentEnterprise is null" +
              " and o.enterprise.id = o.id " +
              " and o.userType = :userType" +
              " and (o.mobilePhoneVerified = :status1 or o.mobilePhoneVerified = :status2)" +
              " order by o.id", User.class)
              .setParameter("mobile", mobile)
              .setParameter("status1", User.USER_MOBILE_VERIFIED)
              .setParameter("status2", User.USER_MOBILE_REGISTERED)
              .setParameter("userType", userType)
              .getResultList();

      return users.isEmpty() ? null : users.get(0);
    } else {
      //暂时用不到以下代码 written by yfdai 2019-1-9
      List<User> users = em.createQuery("select o from User o " +
              "where o.mobileNo = :mobile" +
              " and (o.parentEnterprise = :parentId or o.parentEnterprise is null)" +
              " and o.enterprise.id = o.id " +
              " and o.userType = :userType" +
              " and (o.mobilePhoneVerified = :status1 or o.mobilePhoneVerified = :status2)" +
              " order by o.id", User.class)
              .setParameter("mobile", mobile)
              .setParameter("parentId", ownerId)
              .setParameter("status1", User.USER_MOBILE_VERIFIED)
              .setParameter("status2", User.USER_MOBILE_REGISTERED)
              .setParameter("userType", userType)
              .getResultList();

      return users.isEmpty() ? null : users.get(0);
    }
  }

  @Override
  public User getUserByMobile(int enterpriseId, String mobile) {
    var users = em.createQuery("select o from User o " +
                    "where o.mobileNo = :mobile " +
                    "and o.enterprise.id = :enterpriseId" +
                    " order by o.id desc", User.class)
            .setParameter("mobile", mobile)
            .setParameter("enterpriseId", enterpriseId).getResultList();

    return users.isEmpty() ? null : users.get(0);

  }

  @Override
  public int checkIn(UserCheckIn uci) {
    int retVal = 0;

    List<UserCheckIn> ucis = em.createQuery("select u from UserCheckIn u " +
            "where u.enterpriseId = :enterpriseId and u.checkInDate = :checkInDate", UserCheckIn.class)
            .setParameter("enterpriseId", uci.getEnterpriseId())
            .setParameter("checkInDate", uci.getCheckInDate())
            .getResultList();
    if (ucis.size() > 0) {
      retVal = 2;
    } else {

      em.persist(uci);
      em.flush();

      retVal = 100;
    }


    return retVal;
  }

  @Override
  public List<UserCheckIn> getTopFiveCheckIn(int enterpriseId, int times) {

    List<UserCheckIn> ucis = em.createQuery("select u from UserCheckIn u " +
            "where u.enterpriseId = :enterpriseId order by u.checkInDate desc", UserCheckIn.class)
            .setParameter("enterpriseId", enterpriseId)
            .setMaxResults(times)
            .getResultList();

    ucis = ucis == null ? new ArrayList<>() : ucis;

    return ucis;

  }

  @Override
  public void incCheckInPrize(final int ownerId, final int enterpriseId, final int userId, final int continueDays) {
    int statusCode = 0;


    AmountHistory amountHistory = new AmountHistory();

    EnterpriseBalance entBalance = doGetEnterpriseBalance(ownerId, enterpriseId, em);
    int prizeAmount = continueDays * PRIZE_FOR_CHECK_IN;
    if (prizeAmount > MAX_PRIZE_FOR_CHECK_IN) {
      prizeAmount = MAX_PRIZE_FOR_CHECK_IN;
    }

    entBalance.incBitcoinBalance(prizeAmount);

    amountHistory.setUserId(userId);
    amountHistory.setEnterpriseId(enterpriseId);
    amountHistory.setCredit(prizeAmount);
    amountHistory.setRemark("签到淘得的比特币");

    em.merge(entBalance);
    em.persist(amountHistory);


    em.refresh(amountHistory);

    statusCode = prizeAmount;


  }

  @Override
  public Enterprise getEnterpriseById(int id) {

    Enterprise enterprise = em.find(Enterprise.class, id);
    em.refresh(enterprise);
    return enterprise;

  }

  @Override
  public void createLoginHistory(LoginHistory log) {
    em.persist(log);
  }

  @Override
  public int createHistory(int enterpriseId, String username, int functionId, String remark) {
    int retCode = 0;

    if (remark != null && remark.length() > 200) {
      remark = remark.substring(0, 200);
    }

    LoginHistory log = new LoginHistory();
    log.setEnterpriseId(enterpriseId);
    log.setUsername(username);
    log.setFunctionId(functionId);
    log.setMemo(remark);


    em.persist(log);


    retCode = log.getId();


    return retCode;
  }

  @Override
  public List<LoginHistory> searchHistory(final int enterpriseId, String username, CommonSearchCriteria sc) {
    List<LoginHistory> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<LoginHistory> cq = cb.createQuery(LoginHistory.class);
    Root<LoginHistory> root = cq.from(LoginHistory.class);

    Predicate where = cb.conjunction();

    where = cb.and(where, cb.equal(root.get(LoginHistory_.enterpriseId), enterpriseId));
    where = cb.and(where, cb.equal(root.get(LoginHistory_.username), username));


    if (sc.getRemark().length() > 0) {
      where = cb.and(where, cb.like(root.get(LoginHistory_.memo), '%' + sc.getRemark() + '%'));
    }


    cq.where(where);
    List<Order> orderByes = new ArrayList<>();
    orderByes.add(cb.desc(root.get("id")));

    cq.orderBy(orderByes);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<LoginHistory> countRoot = countQuery.from(LoginHistory.class);

    Predicate where0 = cb.conjunction();
    //****
    where0 = cb.and(where0, cb.equal(countRoot.get(LoginHistory_.enterpriseId), enterpriseId));
    where0 = cb.and(where0, cb.equal(countRoot.get(LoginHistory_.username), username));

    if (sc.getRemark().length() > 0) {
      where0 = cb.and(where0, cb.like(countRoot.get(LoginHistory_.memo), '%' + sc.getRemark() + '%'));
    }


    countQuery.select(cb.count(countRoot)).where(where0);
    Long count = em.createQuery(countQuery).getSingleResult();

    int maxResults = count.intValue();
    if (maxResults > 0) {
      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      try {
        results = em.createQuery(cq)
                .setFirstResult(i)
                .setMaxResults(page.getPageSize()).getResultList();

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }


    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  @Override
  public EnterpriseBalance getEnterpriseBalance(int enterpriseId) {

    return doGetEnterpriseBalance(enterpriseId, em);

  }


  /**
   * 修改用户信息
   */
  @Override
  public int updateUser(final int enterpriseId, final int userId, String empname, String email, String mobileNo,
                        String etermUsername, String position, Integer[] deptIds, int status) {
    User user = em.find(User.class, userId);
    if (user == null || user.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("User is not existed.");
    }

    user.setEmpname(empname);
    user.setEmail(email);
    user.setMobileNo(mobileNo);
    user.setEtermUsername(etermUsername);
    user.setPosition(position);
    user.setStatus(status);

    if (userId == enterpriseId) {
      //超级管理员
      user.setStatus(User.USER_STATUS_NORMAL);
    }

    user.getDepartments().clear();
    for (int deptId : deptIds) {
      EntDepartment department = em.find(EntDepartment.class, deptId);
      if (department != null && department.getEnterpriseId() == enterpriseId) {
        user.getDepartments().add(department);
      }
    }

    em.merge(user);

    return user.getId();
  }

  @Override
  public void updateUser(final int enterpriseId, final int id, User rs, int[] wwDeptIds) {
    User user = em.find(User.class, id);
    if (user == null || user.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("User is not existed.");
    }

    user.setEmpname(rs.getEmpname());
    user.setPosition(rs.getPosition());
    user.setMobileNo(rs.getMobileNo());
    user.setGender(rs.getGender());
    user.setEmail(rs.getEmail());
    user.setAvatar(rs.getAvatar());
    user.setStatus(rs.getStatus());
    user.setAlias(rs.getAlias());
    user.setExternalPosition(rs.getExternalPosition());
    user.setAddress(rs.getAddress());
    user.setTelephone(rs.getTelephone());

    if (id == enterpriseId) {
      //超级管理员
      user.setStatus(User.USER_STATUS_NORMAL);
    }

    user.getDepartments().clear();
    for (int deptId : wwDeptIds) {
      List<EntDepartment> departments = em.createQuery("select o from EntDepartment o where o.enterpriseId = :enterpriseId and o.deptId = :deptId", EntDepartment.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("deptId", deptId)
              .getResultList();

      user.getDepartments().addAll(departments);
    }

    em.merge(user);

  }


  @Override
  public int updateCustomer(Customer c) {
    c.setLastUpdate(DateUtil.getCurDateTime());
    em.merge(c);

    return c.getId();
  }

  /**
   * 查找用户角色
   *
   * @param userId 用户id
   */
  @Override
  public Set<String> loadUserRoles(final int userId) {
    Set<String> results = new HashSet<>();


    List<String> results0 = em.createQuery("select distinct o.role from GroupRole o where o.groupInfo in (" +
            "select o1 from Groups o1 where o1.id in (" +
            "select o2.groupInfo.id from GroupUsers o2 where o2.userInfo.id = :userId" +
            ")" +
            ")", String.class)
            .setParameter("userId", userId)
            .getResultList();

    results.addAll(results0);

    User user = em.find(User.class, userId);
    for (EntDepartment d : user.getDepartments()) {
      if (d.getRole() != null && d.getRole().trim().length() > 0) {
        results.add(d.getRole());
      }
    }

    //检查是否为默认管理员
    if (user.getEnterpriseId() == userId) {
      results.add(RoleInfo.ROLE_ADMIN);
    }

    return results;
  }

  @Override
  public List<RolePrivilege> searchPrivileges(final int enterpriseId, final int userId) {
    return em.createQuery("select o from RolePrivilege o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.role in (" +
            "   select distinct o.role from GroupRole o where o.groupInfo in (" +
            "       select o1 from Groups o1 where o1.id in (select o2.groupInfo.id from GroupUsers o2 where o2.userInfo.id = :userId)" +
            ")" +
            ")", RolePrivilege.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("userId", userId)
            .getResultList();
  }

  @Override
  public List<RolePrivilege> searchPrivilegesByRole(int enterpriseId, String role) {
    return em.createQuery("select o from RolePrivilege o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.role = :role", RolePrivilege.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("role", role)
            .getResultList();
  }

  @Override
  public int updateWwUserId(int enterpriseId, int id, String userId) {
    return em.createQuery("update User o set o.wwUserId = :userId " +
            "where o.enterprise.id = :enterpriseId and o.id = :id")
            .setParameter("id", id)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("userId", userId)
            .executeUpdate();
  }

  @Override
  public String getWwUserIdByUsername(int enterpriseId, String username) {
    User user = getUserByUsername(username, enterpriseId);

    return user == null ? "" : user.getWwUserId();
  }

  /**
   * 查找指定用户的 微信绑定信息
   */
  @Override
  public List<UserBindWeixin> getUserBindWeixin(int ownerId, int enterpriseId, int userId) {
    return em.createQuery("select o from UserBindWeixin o " +
            "where o.ownerId = :ownerId and o.enterpriseId = :enterpriseId and o.userId = :userId", UserBindWeixin.class)
            .setParameter("ownerId", ownerId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("userId", userId)
            .getResultList();
  }

  @Override
  public List<Enterprise> searchCustomerTodo(int enterpriseId) {
    return em.createQuery("select o from Enterprise o " +
            "where o.parentEnterprise = :parentId " +
            "and o.wwCorpId is not null " +
            "and o.id not in (select c.customerEnterpriseId from Customer c where c.enterpriseId = :enterpriseId)", Enterprise.class)
            .setParameter("parentId", enterpriseId)
            .setParameter("enterpriseId", enterpriseId)
            .getResultList();
  }

  @Override
  public User getUserByWwUserId(int enterpriseId, String userid) {
    List<User> users = em.createQuery("select o from User o " +
            "where o.enterprise.id = :enterpriseId and o.wwUserId = :userId", User.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("userId", userid)
            .getResultList();
    return users.isEmpty() ? null : users.get(0);
  }

  @Override
  public void createEtermCmdLog(int enterpriseId, int cmdType, String cmd, String openid) {
    EtermCmdLog log = new EtermCmdLog();
    log.setEnterpriseId(enterpriseId);
    log.setCmdType(cmdType);
    log.setRequestStr(cmd);

    em.persist(log);
  }

  @Override
  public int createEtermCmdLog(int enterpriseId, String username, String title, String orderNo) {
    EtermCmdLog log = new EtermCmdLog();
    log.setEnterpriseId(enterpriseId);
    log.setCmdType(2); //接口调用
    log.setTitle(title);
    log.setUsername(username);
    log.setTitle(title);
    log.setOrderNo(orderNo);

    em.persist(log);
    return log.getId();
  }

  /**
   * 重置用户密码
   */
  @Override
  public int resetUserPassword(final int enterpriseId, final String username, final int userId, final String md5Password) {
    int retCode = 0;

    final User user = em.find(User.class, userId);

    if (user.getEnterprise().getId() == enterpriseId) {
      retCode = em.createQuery("update User o set o.password = null, o.md5Password = :md5, o.lastUpdate = :lastUpdate where o.id = :id and o.enterprise.id = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("md5", md5Password)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    } else if (user.getParentEnterprise() == enterpriseId) {
      retCode = em.createQuery("update User o set o.password = null, o.md5Password = :md5, o.lastUpdate = :lastUpdate where o.id = :id and o.parentEnterprise = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("md5", md5Password)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    }

    if (retCode == 1) {
      // 记录日志
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
      log.setOperator(username);
      log.setContent("管理员(" + username + ")重置用户(" + user.getUsername() + ")密码.");

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public UserBindWeixin getUserByOpenid(int enterpriseId, String openid) {
    List<UserBindWeixin> lists = em.createQuery("select o from UserBindWeixin o where o.ownerId = :ownerId and o.weixinOpenId = :openid", UserBindWeixin.class)
            .setParameter("ownerId", enterpriseId)
            .setParameter("openid", openid)
            .getResultList();

    return lists.size() > 0 ? lists.get(0) : null;
  }

  @Override
  public int createUserBindWeixin(int ownerId, String openid, int enterpriseId, int userId, String username) {
    UserBindWeixin o = new UserBindWeixin();

    o.setOwnerId(ownerId);
    o.setWeixinOpenId(openid);
    o.setEnterpriseId(enterpriseId);
    o.setUsername(username);
    o.setUserId(userId);

    em.persist(o);

    return o.getId();
  }



  @Override
  public int disableUser(int enterpriseId, String username, int userId) {
    int retCode = 0;

    final User user = em.find(User.class, userId);

    if (user.getEnterprise().getId() == enterpriseId) {
      retCode = em.createQuery("update User o set o.status = :status, o.lastUpdate = :lastUpdate where o.id = :id and o.enterprise.id = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status", 4)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    } else if (user.getParentEnterprise() == enterpriseId) {
      retCode = em.createQuery("update User o set o.status = :status, o.lastUpdate = :lastUpdate where o.id = :id and o.parentEnterprise = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status", 4)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    }

    if (retCode == 1) {
      // 记录日志
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
      log.setOperator(username);
      log.setContent("管理员(" + username + ")停用用户(" + user.getUsername() + ").");

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int enableUser(int enterpriseId, String username, int userId) {
    int retCode = 0;

    final User user = em.find(User.class, userId);

    if (user.getEnterprise().getId() == enterpriseId) {
      retCode = em.createQuery("update User o set o.status = :status, o.lastUpdate = :lastUpdate where o.id = :id and o.enterprise.id = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status", 1)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    } else if (user.getParentEnterprise() == enterpriseId) {
      retCode = em.createQuery("update User o set o.status = :status, o.lastUpdate = :lastUpdate where o.id = :id and o.parentEnterprise = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status", 1)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    }

    if (retCode == 1) {
      // 记录日志
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
//      log.setEnterpriseId(enterpriseId);
      log.setOperator(username);
      log.setContent("管理员(" + username + ")启用用户(" + user.getUsername() + ").");

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int updateUserUsername(final int enterpriseId, final String username, final int userId, final String newUsername) {
    int retCode = 0;

    final User user = em.find(User.class, userId);
    final String oldUsername = user.getUsername();

    if (!User.testTemporaryUsername(oldUsername)) {
      //非临时用户名
      throw new RuntimeException("None temporary username can be rename.");
    }

    if (user.getEnterprise().getId() == enterpriseId) {
      retCode = em.createQuery("update User o set o.username = :username, o.lastUpdate = :lastUpdate where o.id = :id and o.enterprise.id = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("username", newUsername)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    } else if (user.getParentEnterprise() == enterpriseId) {
      retCode = em.createQuery("update User o set o.username = :username, o.lastUpdate = :lastUpdate where o.id = :id and o.parentEnterprise = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("username", newUsername)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    }

    if (retCode == 1) {
      // 记录日志
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_BASIC_DATA);
      log.setOperator(username);
      log.setContent("修改用户(" + oldUsername + ")的用户名为 " + newUsername);

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int updateUserEtermUsername(final int enterpriseId, final String username, final int userId, final String etermUsername) {
    int retCode = 0;

    final User user = em.find(User.class, userId);
    final String oldUsername = user.getUsername();

    if (user.getEnterprise().getId() == enterpriseId) {
      retCode = em.createQuery("update User o set o.etermUsername = :etermUsername, o.lastUpdate = :lastUpdate where o.id = :id and o.enterprise.id = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("etermUsername", etermUsername)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    } else if (user.getParentEnterprise() == enterpriseId) {
      retCode = em.createQuery("update User o set o.etermUsername = :etermUsername, o.lastUpdate = :lastUpdate where o.id = :id and o.parentEnterprise = :enterpriseId")
              .setParameter("id", userId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("etermUsername", etermUsername)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
    }

    if (retCode == 1) {
      // 记录日志
      LoginHistory log = new LoginHistory();
      log.setEnterpriseId(enterpriseId);
      log.setUsername(oldUsername);
      log.setMemo("管理员(" + username + ")修改本用户的eterm用户名为 " + etermUsername);

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int updateUserEmail(final int ownerId, final String username, final int userId, final String email) {
    final User user = em.find(User.class, userId);
    String oldEmail = user.getEmail();

    if (user.getEnterpriseId() != ownerId && user.getParentEnterprise() != ownerId) {
      throw new RuntimeException("User is not existed.");
    }

    user.setEmail(email);
    user.setLastUpdate(DateUtil.getCurDateTime());

    OperationLog log = OperationLog.createLog(ownerId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("修改用户(" + user.getUsername() + ")的电子邮件(" + oldEmail + ")为" + email);
    em.persist(log);

    return log.getId();
  }

  @Override
  public int updateUserMobile(int ownerId, String username, int userId, String mobile) {
    final User user = em.find(User.class, userId);
    String oldMobile = user.getMobileNo();

    if (user.getEnterpriseId() != ownerId && user.getParentEnterprise() != ownerId) {
      throw new RuntimeException("User is not existed.");
    }

    user.setMobileNo(mobile);
    user.setLastUpdate(DateUtil.getCurDateTime());

    OperationLog log = OperationLog.createLog(ownerId, OPERATING_OBJECT_BASIC_DATA);
    log.setOperator(username);
    log.setContent("修改用户(" + user.getUsername() + ")的手机号(" + oldMobile + ")为" + mobile);
    em.persist(log);

    return log.getId();
  }

  @Override
  public List<User> searchUsersByMobile(String mobile) {
    return em.createQuery("select o from User o where o.mobileNo = :mobile and o.id = o.enterpriseId order by o.id desc", User.class)
            .setParameter("mobile", mobile)
            .getResultList();
  }

  @Override
  public List<User> searchUsersByDepartment(int enterpriseId, int departmentId) {
    return em.createQuery("select o from User o join o.departments d " +
            "where o.enterpriseId = :enterpriseId and d.deptId = :deptId " +
            "  order by o.id desc", User.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("deptId", departmentId)
            .getResultList();
  }

  @Override
  public void updateEtermCmdLog(int queryId, String requestStr, String responseStr) {
    em.createQuery(
                    "update EtermCmdLog o set " +
                            "o.requestStr = :rq, " +
                            "o.responseStr = :rs, " +
                            "o.lastUpdate = :lastUpdate where o.id = :id")
            .setParameter("id", queryId)
            .setParameter("rq", requestStr)
            .setParameter("rs", responseStr)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();
  }

  @Override
  public int createTmsTask(TmsTask tmsTask) {
    em.persist(tmsTask);
    return tmsTask.getId();
  }

  @Override
  public int createTmsTaskLog(TmsTaskLog log) {
    em.persist(log);
    return log.getId();
  }

  @Override
  public TmsTask getTmsTaskById(int id) {
    return em.find(TmsTask.class, id);
  }

  @Override
  public int unbindWeixinUser(int ownerId, String openId) {
    return em.createQuery("delete from UserBindWeixin o where o.ownerId = :ownerId and o.weixinOpenId = :openId")
            .setParameter("ownerId", ownerId)
            .setParameter("openId", openId)
            .executeUpdate();
  }

  @Override
  public void createTmsWwUser(TmsWwUser tmsWwUser) {
    em.persist(tmsWwUser);
  }

  @Override
  public List<AmountHistory> searchTransactionHistory(final int enterpriseId, CommonSearchCriteria sc) {
    List<AmountHistory> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<AmountHistory> cq = cb.createQuery(AmountHistory.class);
    Root<AmountHistory> root = cq.from(AmountHistory.class);
    root.alias("o");

    List<Predicate> predicates = new ArrayList<>();
    Predicate where = cb.conjunction();
    predicates.add(where);

    int enterpriseId1 = 0;

    if (enterpriseId == Enterprise.ENTERPRISE_PLATFORM_ADMINISTRATOR) {
      if (sc.getEnterpriseId() > 0) {
        enterpriseId1 = sc.getEnterpriseId();
      } else {
        enterpriseId1 = enterpriseId;
      }
    } else {
      if (sc.getEnterpriseId() > 0) {
        //判断要查询的客户是否操作者的下属企业
        Enterprise enterprise = em.find(Enterprise.class, sc.getEnterpriseId());
        if (enterprise.getParentEnterprise() == enterpriseId) {
          enterpriseId1 = sc.getEnterpriseId();
        }
      } else {
        enterpriseId1 = enterpriseId;
      }
    }

    where = cb.equal(root.get(AmountHistory_.enterpriseId), enterpriseId1);
    predicates.add(where);


    if (sc.getStatus() > 0) {
      where = cb.equal(root.get(AmountHistory_.orderType), sc.getStatus());
      predicates.add(where);
    }

    if (sc.getType() == 0) {
      //现金账户
      where = cb.notEqual(root.get(AmountHistory_.orderType), 10);
      predicates.add(where);
    } else if (sc.getType() == 1) {
      //积分账户
      where = cb.equal(root.get(AmountHistory_.orderType), 10);
      predicates.add(where);
    }

    if (sc.getRemark() != null && sc.getRemark().trim().length() > 0) {
      where = cb.like(root.get(AmountHistory_.remark), "%" + sc.getRemark().trim() + "%");
      predicates.add(where);
    }


    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<AmountHistory> countRoot = countQuery.from(AmountHistory.class);
    countRoot.alias("o");

    countQuery.select(cb.count(countRoot)).where(predicates.toArray(new Predicate[predicates.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    int maxResults = count.intValue();
    if (maxResults > 0) {
      cq.where(predicates.toArray(new Predicate[predicates.size()]));

      List<Order> orderByes = new ArrayList<>();
      orderByes.add(cb.desc(root.get("id")));
      cq.orderBy(orderByes);

      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      results = em.createQuery(cq)
              .setFirstResult(i)
              .setMaxResults(page.getPageSize()).getResultList();

    }
    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }
}
